home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / wtek0693.zip / OOPALLEY.ZIP / DATE.CPP < prev    next >
C/C++ Source or Header  |  1993-04-27  |  17KB  |  551 lines

  1. #include "date.h"
  2. #include "strclass.h"
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include "oopsconf.h"   //-gmv Added for conditional compilation
  7.                         //     of code for todays date
  8.                         //     See Date::Date()
  9. #include "object.h"
  10. //#define BORLAND // -gmv 3/29/90 as above
  11.  
  12. #define THIS    Date
  13. #define BASE    Object
  14. DEFINE_CLASS(Date,Object);
  15.  
  16.  
  17. static const unsigned char days_in_month[12] =
  18. {
  19.     31,28,31,30,31,30,31,31,30,31,30,31
  20. };
  21. static const dayTy first_day_of_month[12] =
  22. {
  23.     1,32,60,91,121,152,182,213,244,274,305,335
  24. };
  25. static const char* month_names[12] =
  26. {
  27.     "January",  "February",     "March",
  28.     "April",    "May",          "June",
  29.     "July",     "August",       "September",
  30.     "October",  "November",     "December"
  31. };
  32. static const char* uc_month_names[12] =
  33. {
  34.     "JANUARY",  "FEBRUARY",     "MARCH",
  35.     "APRIL",    "MAY",          "JUNE",
  36.     "JULY",     "AUGUST",       "SEPTEMBER",
  37.     "OCTOBER",  "NOVEMBER",     "DECEMBER"
  38. };
  39. static const char* week_day_names[7] =
  40. {
  41.     "Monday",   "Tuesday",  "Wednesday",
  42.     "Thursday", "Friday",   "Saturday",
  43.     "Sunday"
  44. };
  45. static const char* uc_week_day_names[7] =
  46. {
  47.     "MONDAY",   "TUESDAY",  "WEDNESDAY",
  48.     "THURSDAY", "FRIDAY",   "SATURDAY",
  49.     "SUNDAY"
  50. };
  51. //static const unsigned int seconds_in_day = 24*60*60;
  52. static const unsigned long seconds_in_day = 24L*60*60; //-gmv made long
  53.  
  54. void Date::setDate(int dayCount, yearTy referenceYear)
  55. //////////////////////////////////////////////////////
  56. /////  Set the day and year of a Date object to  /////
  57. /////  the dayCount day  of the referenceYear.   /////
  58. /////  The dayCount may be <= 0, in which case   /////
  59. /////  the Date is that of a year prior to the   /////
  60. /////  referenceYear.                            /////
  61. //////////////////////////////////////////////////////
  62. {
  63.     register int day = dayCount;
  64.     register unsigned year = referenceYear;
  65.     register unsigned yearDays;
  66.     while (day > (yearDays = daysInYear(year))) {
  67.         year++;
  68.         day -= yearDays;
  69.     }
  70.     while (day<=0) day += daysInYear(--year);
  71.     dy = day; yr = year;
  72. }
  73.  
  74. Date::Date()
  75. //////////////////////////////////////////////
  76. //////    Construct a Date for today.   //////
  77. //////////////////////////////////////////////
  78. {
  79.     time_t clk = time(&clk);
  80.     register tm* now = localtime(&clk);
  81.     setDate(now->tm_yday+1, now->tm_year+1900);
  82. }
  83.  
  84. Date::Date(int dayCount, yearTy referenceYear)
  85. //////////////////////////////////////////////
  86. ////////// Construct a Date         //////////
  87. ////////// that is dayCount days    //////////
  88. ////////// after the beginning of   //////////
  89. ////////// the reference year.      //////////
  90. //////////////////////////////////////////////
  91. {
  92.     setDate(dayCount,referenceYear);
  93. }
  94.  
  95. //Date::Date(int dayCount)
  96. Date::Date(long dayCount)  //-gmv
  97. ///////////////////////////////////
  98. /////  Construct a Date       /////
  99. /////  that is dayCount days  /////
  100. /////  after January 1, 1901. /////
  101. ///////////////////////////////////
  102. {
  103.     setDate(1 + (dayCount>=0 ? dayCount%1461 : -((-dayCount)%1461)),
  104.         1901 + 4*((dayCount>=0) ? dayCount/1461 : -((-dayCount)/1461)));
  105. }
  106.  
  107. ////////////////////////////////////////////////////////////
  108. // 4/24/93 -gmv
  109. // The following function was added to resolve ambiguity
  110. // in the statement cerr << this
  111. // between 'operator <<(ostream &,void *)'
  112. //     and 'operator <<(ostream &,const void *)'
  113. // when 'this' is printed in Date::Date.
  114. // The ambiguity is resolved by providing an
  115. // operator<< function which accepts a pointer
  116. // to an Object (rather than a void pointer)
  117. // as its second argument.
  118. ////////////////////////////////////////////////////////////
  119. inline  ostream _FAR & _Cdecl operator<<(ostream &o, Object /* far */ *p)
  120. {
  121.     return operator<<(o, (void*) p);
  122. }
  123.  
  124. Date::Date(dayTy day, const char* monthName, yearTy year)
  125. /////////////////////////////////////
  126. /////  Construct a Date object  /////
  127. /////  for the specified day,   /////
  128. /////  monthName, and year.     /////
  129. /////////////////////////////////////
  130. {
  131.     if (year < 100) year += 1900;
  132.     unsigned monthNumber = numberOfMonth(monthName);
  133.     unsigned daysInMonth  = days_in_month[monthNumber-1];
  134.     if (monthNumber == 2 && leapYear(year)) daysInMonth++;
  135.     unsigned firstDayOfMonth = first_day_of_month[monthNumber-1];
  136.     if (monthNumber > 2 && leapYear(year)) firstDayOfMonth++;
  137.     //if (day<1 || day>daysInMonth)
  138.     //    setOOPSerror(OOPS_BADMODAY,DEFAULT,this,day,monthName,year);
  139.     //if (day<1 || day>daysInMonth)
  140.     //    DTerror("Invalid day of month: ", className());
  141.     if (day<1 || day>daysInMonth)
  142.     {
  143.         DTerror("","");
  144.         cerr << "Invalid day of month: "
  145.              ///////////////////////////////////////////////
  146.              // 4/24/93 -gmv had to add inline function
  147.              // above to resolve ambiguity for cerr << this
  148.              // between 'operator <<(ostream &,void *)'
  149.              //     and 'operator <<(ostream &,const void *)'
  150.              ///////////////////////////////////////////////
  151.              << this << "->Date::Date("
  152.              << day << ","
  153.              << monthName << ","
  154.              << year << ")"
  155.              << "\n";
  156.     }
  157.     setDate(day-1+firstDayOfMonth,year);
  158. }
  159.  
  160. static void skipDelim(istream& strm)
  161. {
  162.     char c;
  163.     if (!strm.good()) return;
  164.     strm >> c;
  165.     while (strm.good() && !isalnum(c)) strm >> c;
  166.     strm.putback(c);
  167. }
  168.  
  169. static const char* parseMonth(istream& strm)
  170. ////////////////////////////////////////////
  171. /////  Read the name of a month from   /////
  172. /////  the specified input stream.     /////
  173. ////////////////////////////////////////////
  174. {
  175.     static char month[10];
  176.     register char* p = month;
  177.     char c;
  178.     skipDelim(strm);
  179.     strm.get(c);
  180.     while (strm.good() && isalpha(c) && (p != &month[10])) {
  181.         *p++ = c;
  182.         strm.get(c);
  183.     }
  184.     if (strm.good()) strm.putback(c);
  185.     *p = '\0';
  186.     return month;
  187. }
  188.  
  189. static Date parseDate(istream& strm)
  190. ////////////////////////////////////////////////////////////////////
  191. /////  Read a date from the specified                          /////
  192. /////  input stream in any of the                              /////
  193. /////  following forms:                                        /////
  194. /////                                                          /////
  195. /////    <day><monthName><year>      (5 April 1982; 5-APR-82)  /////
  196. /////    <monthName><day><year>      (April 5, 1982)           /////
  197. /////    <monthNumber><day><year>    (4/5/82)                  /////
  198. ////////////////////////////////////////////////////////////////////
  199. {
  200.     unsigned d,m,y;
  201.     const char* mon;        // name of month
  202.     if (strm.good()) {
  203.         skipDelim(strm);
  204.         strm >> m;      // try to parse day or month number
  205.         skipDelim(strm);
  206.         if (strm.eof()) return Date(1,1901);
  207.         if (strm.fail()) {  // parse <monthName><day><year>
  208.             strm.clear();
  209.             mon = parseMonth(strm); // parse month name
  210.             skipDelim(strm);
  211.             strm >> d;      // parse day
  212.         }
  213.         else {          // try to parse day number
  214.             strm >> d;
  215.             if (strm.eof()) return Date(1,1901);
  216.             if (strm.fail()) {  // parse <day><monthName><year>
  217.                 d = m;
  218.                 strm.clear();
  219.                 mon = parseMonth(strm);     // parse month name
  220.             }
  221.             else {          // parsed <monthNumber><day><year>
  222.                 mon = nameOfMonth(m);
  223.             }
  224.         }
  225.         skipDelim(strm);
  226.         strm >> y;
  227.     }
  228.     if (!strm.good()) return Date(1,1901);
  229.     return Date(d,mon,y);
  230. }
  231.  
  232. Date::Date(istream& strm)   { *this = parseDate(strm); }
  233.  
  234. dayTy dayOfWeek(const char* dayName)
  235. //////////////////////////////////////
  236. /////  Returns the number, 1-7,  /////
  237. /////  of the day of the week    /////
  238. /////  named dayName.            /////
  239. //////////////////////////////////////
  240. {
  241.     {
  242.         String s(dayName);
  243.         register unsigned len = s.size();
  244.         if (len > 2) {
  245.             s.toUpper();
  246.             register const char* p = s;
  247.             for (register unsigned i =0; i<7; i++)
  248.             if (strncmp(p,uc_week_day_names[i],len)==0) return i+1;
  249.         }
  250.     }
  251.     //setOOPSerror(OOPS_BADDAYNAM,DEFAULT,dayName);
  252.     //DTerror("Date: Invalid day of week: ", dayName);
  253.     DTerror("","");
  254.     cerr << "Invalid day of week name: "
  255.          << dayName
  256.          << "\n";
  257.     return 0;   // never executed
  258. }
  259.  
  260. dayTy daysInYear(yearTy year)
  261. ////////////////////////////////////////
  262. /////  Returns the number of days  /////
  263. /////  in the specified year.      /////
  264. ////////////////////////////////////////
  265. {
  266.     return leapYear(year) ? 366 : 365;
  267. }
  268.  
  269. monthTy numberOfMonth(const char* monthName)
  270. ///////////////////////////////////////////
  271. /////  Returns the number, 1-12,      /////
  272. /////  of the month named monthName.  /////
  273. ///////////////////////////////////////////
  274. {
  275.     {
  276.         String s(monthName);
  277.         register unsigned len = s.size();
  278.         if (len > 2) {
  279.             s.toUpper();
  280.             register const char* p = s;
  281.             for (register unsigned i =0; i<12; i++)
  282.                 if (strncmp(p,uc_month_names[i],len)==0) return i+1;
  283.         }
  284.     }
  285.     //setOOPSerror(OOPS_BADMONAM,DEFAULT,monthName);
  286.     //DTerror("Invalid month name", monthName);
  287.     DTerror("","");
  288.     cerr << "Invalid month name: "
  289.          << monthName
  290.          << "\n";
  291.     return 0;   // never executed
  292. }
  293.  
  294. bool leapYear(yearTy year)
  295. //////////////////////////////////////////
  296. /////  Returns YES if the specified  /////
  297. /////  year is a leap year.          /////
  298. //////////////////////////////////////////
  299. {
  300.     return ((year&3) == 0 && year%100 != 0 || year%400 == 0);
  301. }
  302.  
  303. const char* nameOfMonth(monthTy monthNumber)
  304. /////////////////////////////////////////
  305. /////  Returns the name of the      /////
  306. /////  month numbered monthNumber.  /////
  307. /////////////////////////////////////////
  308. {
  309.     //if (--monthNumber >= 12)
  310.     //    setOOPSerror(OOPS_BADMONTH,DEFAULT,monthNumber+1);
  311.     //if (--monthNumber >= 12)
  312.     //    DTerror("Invalid month", "");
  313.     if (--monthNumber >= 12)
  314.     {
  315.         DTerror("","");
  316.         cerr << "Invalid month: "
  317.              << monthNumber+1
  318.              << "\n";
  319.     }
  320.     return month_names[monthNumber];
  321. }
  322.  
  323. const char* nameOfDay(dayTy weekDayNumber)
  324. ////////////////////////////////////////////////
  325. /////  Returns the name of the day         /////
  326. /////  specified by weekDayNumber:         /////
  327. /////      Monday == 1, ... , Sunday == 7  /////
  328. ////////////////////////////////////////////////
  329. {
  330.     //if (--weekDayNumber >= 7)
  331.     //    setOOPSerror(OOPS_BADDAY,DEFAULT,weekDayNumber+1);
  332.     //if (--weekDayNumber >= 7)
  333.     //    DTerror("Invalid day of week: ", "");
  334.     if (--weekDayNumber >= 7)
  335.     {
  336.         DTerror("","");
  337.         cerr << "Invalid day of week: "
  338.              << weekDayNumber+1
  339.              << "\n";
  340.     }
  341.     return week_day_names[weekDayNumber];
  342. }
  343.  
  344. bool Date::operator<(Date dt) const
  345. //////////////////////////////
  346. // Return YES if this Date  //
  347. // is < the argument Date.  //
  348. //////////////////////////////
  349. {
  350.     if (yr < dt.yr) return YES;
  351.     if (yr == dt.yr && dy < dt.dy) return YES;
  352.     return NO;
  353. }
  354.  
  355. bool Date::operator<=(Date dt) const
  356. //////////////////////////////
  357. // Return YES if this Date  //
  358. // is <= the argument Date. //
  359. //////////////////////////////
  360. {
  361.     if (yr < dt.yr) return YES;
  362.     if (yr == dt.yr && dy <= dt.dy) return YES;
  363.     return NO;
  364. }
  365.  
  366. //int Date::operator-(Date dt)
  367. long Date::operator-(Date dt) const
  368. ////////////////////////////////////////
  369. /////  Return the number of days   /////
  370. /////  between this Date and       /////
  371. /////  the argument.  The result   /////
  372. /////  is negative if the argument /////
  373. /////  is later.                   /////
  374. ////////////////////////////////////////
  375. {
  376.     Date a(*this),b(dt);
  377. //    const Date a(*this), b(dt); // -gmv 5/2/90 made const
  378.     bool negative = b > a;
  379.     if (negative)
  380.     {
  381.         a = b;
  382.         b = *this;
  383.     }
  384.     unsigned year = b.year();
  385.     long days = signed(a.day()-b.day()); //-gmv
  386.     while (year != a.year()) days += daysInYear(year++);
  387.     return negative ? -days : days;
  388. }
  389.  
  390. const char* Date::nameOfMonth() const
  391. {
  392.     return ::nameOfMonth(month());
  393. }
  394.  
  395. monthTy Date::month() const
  396. ///////////////////////////////////////
  397. /////  Returns the number, 1-12,  /////
  398. /////  of this Date's month.      /////
  399. ///////////////////////////////////////
  400. {
  401. //register bool leapYear = leap();  // -gmv 5/2/90 Why is this here?
  402.     register unsigned firstDay;
  403.     for (register unsigned mn =12; mn>0; mn--) {
  404.         firstDay = first_day_of_month[mn-1];
  405.         if (mn > 2 && leap()) firstDay++;
  406.         if (firstDay <= dy) return mn;
  407.     }
  408.     //setOOPSerror(OOPS_BADMONTH,DEFAULT,mn);
  409.     //DTerror("Invalid month: ", className());
  410.     DTerror("","");
  411.     cerr << "Invalid month: "
  412.          << mn
  413.          << "\n";
  414.     return 0;   // never executed
  415. }
  416.  
  417. dayTy Date::firstDayOfMonth(monthTy month) const
  418. ///////////////////////////////////////////////
  419. /////  Returns the number of the day      /////
  420. /////  of the year that is the first day  /////
  421. /////  of the month in this Date's year.  /////
  422. ///////////////////////////////////////////////
  423. {
  424.     register unsigned firstDay = first_day_of_month[month-1];
  425.     if (month > 2 && leap()) firstDay++;
  426.     return firstDay;
  427. }
  428.  
  429. Date Date::previous(const char* dayName) const
  430. ////////////////////////////////////////////
  431. /////  Returns the previous date       /////
  432. /////  whose weekday name is dayName.  /////
  433. ////////////////////////////////////////////
  434. {
  435.     return *this - (7 + weekDay() - dayOfWeek(dayName))%7;
  436. }
  437.  
  438. dayTy Date::weekDay() const
  439. /////////////////////////////////////
  440. /////  Return the number, 1-7,  /////
  441. /////  of the day of the week   /////
  442. /////  for this Date.           /////
  443. /////////////////////////////////////
  444. {
  445.     register unsigned yearNumber;
  446.     register unsigned dayNumber;
  447.     if (dy < firstDayOfMonth(3)) {
  448.         yearNumber = yr-1;
  449.         dayNumber = 307;
  450.         }
  451.     else {
  452.         yearNumber = yr;
  453.         dayNumber = -58-leap();
  454.     }
  455.     return (dayNumber + dy + yearNumber
  456.             + (yearNumber/4) + (yearNumber/400)
  457.             - (yearNumber/100)) % 7 + 1;
  458. }
  459.  
  460. bool Date::between(Date min, Date max) const
  461. /////////////////////////////////////////
  462. /////  Return YES if this Date      /////
  463. /////  is <= to max and >= to min.  /////
  464. /////////////////////////////////////////
  465. {
  466.     return *this >= min && *this <= max;
  467. }
  468.  
  469. dayTy Date::dayOfMonth() const
  470. {
  471.     return dy-firstDayOfMonth()+1;
  472. }
  473.  
  474. Date Date::max(Date dt) const
  475. {
  476.     if (dt < *this)
  477.         return *this;
  478.     return dt;
  479. }
  480.  
  481. Date Date::min(Date dt) const
  482. {
  483.     if (dt > *this)
  484.         return *this;
  485.     return dt;
  486. }
  487.  
  488. int Date::compare(const Object& ob) const
  489. {
  490.     int t;
  491.     assertArgSpecies(ob,class_Date,"compare");
  492.     if ((t=yr-((Date*)&ob)->yr) != 0) return t;
  493.     else return (dy-((Date*)&ob)->dy);
  494. }
  495.  
  496. Object* Date::copy() const       { return shallowCopy(); }
  497.  
  498. void Date::deepenShallowCopy()  {}
  499.  
  500. unsigned Date::hash() const   { return dy^yr; }
  501.  
  502. bool Date::isEqual(const Object& ob) const
  503. {
  504.     return ob.isSpecies(class_Date) && *this==*(Date*)&ob;
  505. }
  506.  
  507. const Class* Date::species() const    { return &class_Date; }
  508.  
  509. void Date::printOn(ostream& strm) const
  510. {
  511. #if 0
  512.     strm << form("%2d-%.3s-%.2d",
  513.         dayOfMonth(),
  514.         nameOfMonth(),
  515.         yr%100);
  516. #else
  517.     char saveFillChar = strm.fill();
  518.     long saveFlags = strm.flags();
  519.     strm.width(2);
  520.     strm.fill(' ');
  521.     strm << dayOfMonth() << "-";
  522.  
  523.     char monthAbbreviation[4];
  524.     strncpy(monthAbbreviation, nameOfMonth(), 3);
  525.     monthAbbreviation[3] = '\0';
  526.     strm << monthAbbreviation << "-";
  527.     //strm  << nameOfMonth() << "-";
  528.  
  529.     strm.width(2);
  530.     strm.fill('0');
  531.     strm << yr%100;
  532.     strm.fill(saveFillChar);
  533.     strm.flags(saveFlags);
  534. #endif
  535. }
  536.  
  537. void Date::scanFrom(istream& strm)
  538. {
  539.     *this = parseDate(strm);
  540. }
  541.  
  542. #if 0
  543. Date::Date(istream& strm, Date& where)
  544. {
  545.     this = &where;
  546.     strm >> dy >> yr;
  547. }
  548. // -gmv stripped 5/3/90
  549. #endif
  550.  
  551.